package com.ruoyi.common.utils.parameter;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * QPS 限流
 * 使用数组存储每个请求到来的时间，前10次请求顺利通过，并填满数组。
 * 后续请求到来时，判断当前时间是否比数组中最早的时间晚1s，未晚，则打回，
 * 晚则替换数组中最早的值。循环。
 */
public class QpsControlUtil {

	/**
	 * 接受请求窗口
	 */
	private Long[] accessWindow;
	/**
	 * qps限制次数
	 */
	private static final int limit = 10;
	/**
	 * 指针位置
	 */
	private int curPosition;
	/**
	 * 时间间隔
	 */
	private static final long period = TimeUnit.SECONDS.toMillis(1);

	private final Object lock = new Object();

	private static class SingletonHolder {
		private static final QpsControlUtil SINGLETON = new QpsControlUtil();
	}

	/**
	 * 单例方法入口
	 * @return 单例类
	 */
	public static QpsControlUtil getInstance() {
		return SingletonHolder.SINGLETON;
	}

	/**
	 * 1秒内最多20次请求
	 */
	public QpsControlUtil() {
		curPosition = 0;
		accessWindow = new Long[limit];
		Arrays.fill(accessWindow, 0L);
	}

	public boolean isPass(int limit) {
		long curTime = System.currentTimeMillis();
		synchronized (lock) {
			if (curTime >= period + accessWindow[curPosition]) {
				accessWindow[curPosition++] = curTime;
				curPosition = curPosition % limit;
				return true;
			} else {
				return false;
			}
		}
	}


	public static void main(String[] args) {
		for (int i = 0; i < 20; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName()+ "......bb");
					for (int i = 0; i < 5; i++) {
						//                        System.out.println("第" + (i+1) + "个请求访问情况：" + QpsControlUtil.getInstance().isPass());
						long t1 = System.currentTimeMillis();
						boolean flag = QpsControlUtil.getInstance().isPass(1);
						if (!flag) {
							try {
								System.out.println("满了停止1秒");
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
						System.out.println(Thread.currentThread().getName() + "第" + (i+1) + "个请求访问情况：" + flag + ",时间间隔："+ (System.currentTimeMillis()-t1));
					}
				}
			}).start();

		}
	}
}
